package com.andy.compiler;

import com.andy.annotation.BindValue;

import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.tools.JavaFileObject;

public class BindViewProcessor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(BindValue.class);
        Map<String, List<VariableElement>> map = new HashMap<>();
        for (Element element : elements) {
            VariableElement variableElement = (VariableElement) element;
            String clsName = variableElement.getEnclosingElement().getSimpleName().toString();
            List<VariableElement> list = map.get(clsName);
            if (list == null) {
                list = new ArrayList<>();
                map.put(clsName, list);
            }
            list.add(variableElement);
        }
        if (map.size() > 0) {
            for (String key : map.keySet()) {
                List<VariableElement> list = map.get(key);
                //获取类元素
                TypeElement enclosingElement = (TypeElement) list.get(0).getEnclosingElement();
                //获取类的包名
                String packageName = processingEnv.getElementUtils().getPackageOf(enclosingElement).toString();
                //生成对应的类
//                generateClass(list, packageName, key);
            }
        }
        return false;
    }

//    /**
//     * 根据注解信息生成对应的类，本方法中手动生成类文件内容
//     * 我们还可以使用第三方工具JavaPoet优雅的生成，具体参考地址：https://github.com/square/javapoet
//     *
//     * @param variableElements 设置了对应注解的属性元素的集合
//     * @param packageName      包名
//     * @param activityName     类名
//     */
//    private void generateClass(List<VariableElement> variableElements, String packageName, String activityName) {
//        Writer writer = null;
//        try {
//            JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(packageName + "." + activityName + "_ViewBinding");
//            writer = sourceFile.openWriter();
//            //包名
//            writer.write("package " + packageName + ";\n");
//            //导入包
//            writer.write("import com.payne.buf.IBinder;\n");
//            //类名以及实现的接口名
//            writer.write("public class " + activityName + "_ViewBinding implements IBinder<"
//                    + packageName + "." + activityName + "> {\n");
//            //实现接口中的方法
//            writer.write("  @Override\n");
//            writer.write("  public void bind(" + packageName + "." + activityName + " target) {\n");
//            //遍历属性元素集合，根据信息生成findViewById操作
//            for (VariableElement variableElement : variableElements) {
//                String variableName = variableElement.getSimpleName().toString();
//                String id = variableElement.getAnnotation(BindValue.class).value();
//                TypeMirror typeMirror = variableElement.asType();
//                writer.write("      target." + variableName + " = (" + typeMirror + ") target.findViewById(" + id + ");\n");
//            }
//            writer.write("  }\n");
//            writer.write("}\n");
//        } catch (IOException e) {
//            e.printStackTrace();
//        } finally {
//            if (writer != null) {
//                try {
//                    writer.close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//        }
//    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> result = new HashSet<String>();
        result.add(BindValue.class.getName());
        return result;
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return super.getSupportedSourceVersion();
    }
}
